// Copyright Epic Games, Inc. All Rights Reserved.


#include "LyraContextEffectsSubsystem.h"

#include "Feedback/ContextEffects/LyraContextEffectsLibrary.h"
#include "Feedback/ContextEffects/LyraContextEffectsSubsystem.h"
#include "Kismet/GameplayStatics.h"
#include "NiagaraFunctionLibrary.h"
#include "NiagaraSystem.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraContextEffectsSubsystem)

class AActor;
class UAudioComponent;
class UNiagaraSystem;
class USceneComponent;
class USoundBase;

/**
 * 生成上下文效果
 */
void ULyraContextEffectsSubsystem::SpawnContextEffects(
	const AActor* SpawningActor
	, USceneComponent* AttachToComponent
	, const FName AttachPoint
	, const FVector LocationOffset
	, const FRotator RotationOffset
	, FGameplayTag Effect
	, FGameplayTagContainer Contexts
	, TArray<UAudioComponent*>& AudioOut
	, TArray<UNiagaraComponent*>& NiagaraOut
	, FVector VFXScale
	, float AudioVolume
	, float AudioPitch)
{
	// 首先确定此Actor是否有匹配的库集合
	if (TObjectPtr<ULyraContextEffectsSet>* EffectsLibrariesSetPtr = ActiveActorEffectsMap.Find(SpawningActor)) // 查找活动Actor效果映射
	{
		// 验证从映射查找的指针
		if (ULyraContextEffectsSet* EffectsLibraries = *EffectsLibrariesSetPtr) // 获取效果库集合
		{
			// 准备声音和Niagara系统数组
			TArray<USoundBase*> TotalSounds; // 总声音数组
			TArray<UNiagaraSystem*> TotalNiagaraSystems; // 总Niagara系统数组

			// 循环遍历效果库
			for (ULyraContextEffectsLibrary* EffectLibrary : EffectsLibraries->LyraContextEffectsLibraries) // 遍历Lyra上下文效果库
			{
				// 检查效果库是否有效且数据已加载
				if (EffectLibrary && EffectLibrary->GetContextEffectsLibraryLoadState() == EContextEffectsLibraryLoadState::Loaded) // 检查加载状态
				{
					// 设置本地声音和Niagara系统列表
					TArray<USoundBase*> Sounds; // 声音数组
					TArray<UNiagaraSystem*> NiagaraSystems; // Niagara系统数组

					// 获取声音和Niagara系统
					EffectLibrary->GetEffects(Effect, Contexts, Sounds, NiagaraSystems); // 获取效果

					// 追加到累积数组
					TotalSounds.Append(Sounds); // 追加声音
					TotalNiagaraSystems.Append(NiagaraSystems); // 追加Niagara系统
				}
				else if (EffectLibrary && EffectLibrary->GetContextEffectsLibraryLoadState() == EContextEffectsLibraryLoadState::Unloaded) // 如果未加载
				{
					// 否则加载效果
					EffectLibrary->LoadEffects(); // 加载效果
				}
			}

			// 循环遍历找到的声音
			for (USoundBase* Sound : TotalSounds) // 遍历总声音
			{
				// 生成附加声音，添加音频组件到ACs列表
				UAudioComponent* AudioComponent = UGameplayStatics::SpawnSoundAttached(Sound, AttachToComponent, AttachPoint, LocationOffset, RotationOffset, EAttachLocation::KeepRelativeOffset,
					false, AudioVolume, AudioPitch, 0.0f, nullptr, nullptr, true); // 生成附加声音

				AudioOut.Add(AudioComponent); // 添加到音频输出
			}

			// 循环遍历找到的Niagara系统
			for (UNiagaraSystem* NiagaraSystem : TotalNiagaraSystems) // 遍历总Niagara系统
			{
				// 生成附加Niagara系统，添加Niagara组件到NCs列表
				UNiagaraComponent* NiagaraComponent = UNiagaraFunctionLibrary::SpawnSystemAttached(NiagaraSystem, AttachToComponent, AttachPoint, LocationOffset,
					RotationOffset, VFXScale, EAttachLocation::KeepRelativeOffset, true, ENCPoolMethod::None, true, true); // 生成附加系统

				NiagaraOut.Add(NiagaraComponent); // 添加到Niagara输出
			}
		}
	}
}

/**
 * 从表面类型获取上下文
 */
bool ULyraContextEffectsSubsystem::GetContextFromSurfaceType(
	TEnumAsByte<EPhysicalSurface> PhysicalSurface, FGameplayTag& Context)
{
	// 获取项目设置
	if (const ULyraContextEffectsSettings* ProjectSettings = GetDefault<ULyraContextEffectsSettings>()) // 获取上下文效果设置
	{
		// 查找表面类型映射到哪个游戏标签
		if (const FGameplayTag* GameplayTagPtr = ProjectSettings->SurfaceTypeToContextMap.Find(PhysicalSurface)) // 查找表面类型到上下文映射
		{
			Context = *GameplayTagPtr; // 设置上下文
		}
	}

	// 如果上下文有效返回true
	return Context.IsValid(); // 返回上下文有效性
}

/**
 * 加载并添加上下文效果库
 */
void ULyraContextEffectsSubsystem::LoadAndAddContextEffectsLibraries(AActor* OwningActor,
	TSet<TSoftObjectPtr<ULyraContextEffectsLibrary>> ContextEffectsLibraries)
{
	// 如果拥有者Actor无效或关联的库为0（或更少），提前退出
	if (OwningActor == nullptr || ContextEffectsLibraries.Num() <= 0) // 检查拥有者Actor和库数量
	{
		return; // 提前返回
	}

	// 创建新的上下文效果集合
	ULyraContextEffectsSet* EffectsLibrariesSet = NewObject<ULyraContextEffectsSet>(this); // 创建新上下文效果集合

	// 循环遍历库获取软对象引用
	for (const TSoftObjectPtr<ULyraContextEffectsLibrary>& ContextEffectSoftObj : ContextEffectsLibraries) // 遍历上下文效果库
	{
		// 从软对象引用加载库资源
		// TODO 支持资源数据的异步加载
		if (ULyraContextEffectsLibrary* EffectsLibrary = ContextEffectSoftObj.LoadSynchronous()) // 同步加载效果库
		{
			// 在有效库上调用加载
			EffectsLibrary->LoadEffects(); // 加载效果

			// 添加新库到集合
			EffectsLibrariesSet->LyraContextEffectsLibraries.Add(EffectsLibrary); // 添加到Lyra上下文效果库
		}
	}

	// 更新活动Actor效果映射
	ActiveActorEffectsMap.Emplace(OwningActor, EffectsLibrariesSet); // 添加到活动Actor效果映射
}

/**
 * 卸载并移除上下文效果库
 */
void ULyraContextEffectsSubsystem::UnloadAndRemoveContextEffectsLibraries(AActor* OwningActor)
{
	// 如果拥有者Actor无效，提前退出
	if (OwningActor == nullptr) // 检查拥有者Actor
	{
		return; // 提前返回
	}

	// 从活动Actor/效果集合映射中移除引用
	ActiveActorEffectsMap.Remove(OwningActor); // 从活动Actor效果映射中移除
}